module tlv56xxctrl
		(clock, resetn, start, busyn, ADDR, DATA, SCLK, FS, DOUT, LDACn, PREn, MODE);
input			clock, resetn;
input			start;

// Flag signal that indicates D/A conversion is being processed.
output			busyn;

// Address value of DAC data
input	[3:0]	ADDR;
// Data value of DAC data
input	[11:0]	DATA;

// Outputs to external tlv56xx DAC
output			SCLK, FS, DOUT;
output			LDACn;
output			PREn, MODE;

// Sets configuration outputs
assign			LDACn = 0;		// Enable immediate update of DAC output
assign			PREn = 1;		// Disable preset
assign			MODE = 1;		// Set operating mode to microcontroller compatible

reg				busyn;
reg				SCLK, FS, DOUT;

wire			done_dacnt;
wire	[4:0]	DACNT, DACNT_REF;

assign			DACNT_REF = 15;

wire	[15:0]	DATA_SFTREG;

assign			DATA_SFTREG = {ADDR[3:0], DATA[11:0]};

// Definition of states for controlling tlv56xx control generation logics
parameter		IDLE=0, INIT0=1, INITH=2, INITL=3,
				CLKH=4, CLKL=5,
				FIN0=6, FIN1=7, FIN2=8, FIN3=9;
reg		[3:0]	STATE;

// Outputs of the state machine
reg				cnten_dacnt, sclr_dacnt;
reg				clken_sftreg, load_sftreg;
// Besides above registers, SCLK, FS and busyn are also outputs of the state machine

// Initiation of data path logics
lpm_adcnt		lpm_adcnt_inst (.clock(clock), .cnt_en(cnten_dacnt), .sclr(sclr_dacnt), .aclr(~resetn), .q(DACNT));
lpm_adccomp		lpm_adccomp_inst (.dataa(DACNT), .datab(DACNT_REF), .ageb(done_dacnt));
lpm_sftreg_pload lpm_sftreg_pload_inst (.clock(clock), .enable(clken_sftreg),.load(load_sftreg),
										.aclr(~resetn), .data(DATA_SFTREG), .shiftout(DOUT));

always @(posedge clock or negedge resetn)
begin: NEXT_CURR
if (!resetn)
	STATE <= IDLE;
else
	case (STATE)
		IDLE:
			if (start) STATE <= INIT0;
			else STATE <= IDLE;
		INIT0: STATE <= INITH;
		INITH: STATE <= INITL;
		INITL: STATE <= CLKH;
		CLKH: STATE <= CLKL;
		CLKL:
			if (done_dacnt) STATE <= FIN0;
			else STATE <= CLKH;
		FIN0: STATE <= FIN1;
		FIN1: STATE <= FIN2;
		FIN2: STATE <= FIN3;
		FIN3: STATE <= IDLE;
		default: STATE <= IDLE;
	endcase
end

always @(STATE)
begin: STATE_DECODING
case (STATE)
	IDLE:
		begin
			cnten_dacnt  <= 0;    sclr_dacnt <= 0;    load_sftreg <= 0;
			SCLK         <= 0;    FS         <= 1;    busyn       <= 1;
			clken_sftreg <= 0;
		end
	INIT0:
		begin
			cnten_dacnt  <= 0;    sclr_dacnt <= 1;    load_sftreg <= 1;
			SCLK         <= 0;    FS         <= 0;    busyn       <= 0;
			clken_sftreg <= 1;
		end
	INITH:
		begin
			cnten_dacnt  <= 0;    sclr_dacnt <= 0;    load_sftreg <= 0;
			SCLK         <= 1;    FS         <= 0;    busyn       <= 0;
			clken_sftreg <= 0;
		end
	INITL:
		begin
			cnten_dacnt  <= 0;    sclr_dacnt <= 0;    load_sftreg <= 0;
			SCLK         <= 0;    FS         <= 0;    busyn       <= 0;
			clken_sftreg <= 1;
		end
	CLKH:
		begin
			cnten_dacnt  <= 1;    sclr_dacnt <= 0;    load_sftreg <= 0;
			SCLK         <= 1;    FS         <= 0;    busyn       <= 0;
			clken_sftreg <= 0;
		end
	CLKL:
		begin
			cnten_dacnt  <= 0;    sclr_dacnt <= 0;    load_sftreg <= 0;
			SCLK         <= 0;    FS         <= 0;    busyn       <= 0;
			clken_sftreg <= 1;
		end
	FIN0:
		begin
			cnten_dacnt  <= 0;    sclr_dacnt <= 0;    load_sftreg <= 0;
			SCLK         <= 1;    FS         <= 1;    busyn       <= 0;
			clken_sftreg <= 0;
		end
	FIN1:
		begin
			cnten_dacnt  <= 0;    sclr_dacnt <= 0;    load_sftreg <= 0;
			SCLK         <= 0;    FS         <= 1;    busyn       <= 0;
			clken_sftreg <= 0;
		end
	FIN2:
		begin
			cnten_dacnt  <= 0;    sclr_dacnt <= 0;    load_sftreg <= 0;
			SCLK         <= 1;    FS         <= 1;    busyn       <= 0;
			clken_sftreg <= 0;
		end
	FIN3:
		begin
			cnten_dacnt  <= 0;    sclr_dacnt <= 0;    load_sftreg <= 0;
			SCLK         <= 0;    FS         <= 1;    busyn       <= 0;
			clken_sftreg <= 0;
		end
	default:
		begin
			cnten_dacnt  <= 0;    sclr_dacnt <= 0;    load_sftreg <= 0;
			SCLK         <= 0;    FS         <= 1;    busyn       <= 1;
			clken_sftreg <= 0;
		end
endcase
end
endmodule